/**
 * 
 */
package optimization.naturalOptimization.searchSpace;

import java.text.DecimalFormat;

import optimization.naturalOptimization.NaturalOptimization;

/**
 * This class provides the implementation of a double array search space.
 * 
 * @author Kevin Wagner
 * @version 1.0
 */
public class DoubleArraySearchSpace extends SearchSpace<double[]> {
	
	private final double stdLowerBound=Double.MIN_VALUE;
	private final double stdUpperBound=Double.MAX_VALUE;

	/**
	 * Creates a new Search space using the constructor from {@link SearchSpace}
	 * .
	 * 
	 * @param no
	 *            parent optimization
	 */
	public DoubleArraySearchSpace(NaturalOptimization no) {
		super(no);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * optimization.naturalOptimization.searchSpace.SearchSpace#isFeasible(java
	 * .lang.Object)
	 */
	@Override
	public boolean isFeasible(double[] position) {
		if (getBoundaries() == null) {
			return true;
		}
		boolean temp = true;
		for (int i = 0; i < getBoundaries().length; i++) {
			temp = temp && (position[i] > getBoundaries()[i][0])
					&& (position[i] < getBoundaries()[i][1]);
		}
		return temp;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * optimization.naturalOptimization.searchSpace.SearchSpace#createRandomPosition
	 * ()
	 */
	@Override
	public double[] createRandomPosition() {
		double[] temp = new double[getDimensionality()];
		double[][] tempBoundaries = new double[getDimensionality()][2];
		if (getBoundaries() != null) {
			tempBoundaries = getBoundaries();
		} else {
			tempBoundaries=getStandardBounds();
		}
		for (int i = 0; i < getDimensionality(); i++) {
			temp[i] = getParentOptimization().getRng().nextDouble()
					* (tempBoundaries[i][1] - tempBoundaries[i][0])
					+ tempBoundaries[i][0];
		}
		return temp;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * optimization.naturalOptimization.searchSpace.SearchSpace#createRandomPosition
	 * ()
	 */
	@Override
	public double[] createMiddlePosition() {
		double[] temp = new double[getDimensionality()];
		double[][] tempBoundaries = new double[getDimensionality()][2];
		if (getBoundaries() != null) {
			tempBoundaries = getBoundaries();
		} else {
			tempBoundaries=getStandardBounds();
		}
		for (int i = 0; i < getDimensionality(); i++) {
			temp[i] = (tempBoundaries[i][1] + tempBoundaries[i][0])/2.0;
		}
		return temp;
	}
	

	/*
	 * (non-Javadoc)
	 * 
	 * @see optimization.IdentificationI#getIndentification()
	 */
	@Override
	public String getIndentification() {
		String identification = "Double Array Search Space\n    dimensionality: "
				+ getDimensionality() + "\n    boundaries: ";
		if (getBoundaries() == null) {
			identification += "no boundaries";
		} else {
			identification += "set";
		}
		return identification;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see optimization.naturalOptimization.searchSpace.SearchSpace#
	 * createPositiveRandomVector()
	 */
	@Override
	public double[] createPositiveRandomVector() {
		double[] temp = new double[getDimensionality()];
		double[][] tempBoundaries = new double[getDimensionality()][2];
		if (getBoundaries() != null) {
			tempBoundaries = getBoundaries();
		} else {
			tempBoundaries=getStandardBounds();
		}
		for (int i = 0; i < getDimensionality(); i++) {
			temp[i] = getParentOptimization().getRng().nextDouble()
					* Math.abs(tempBoundaries[i][1] - tempBoundaries[i][0]);
		}
		return temp;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * optimization.naturalOptimization.searchSpace.SearchSpace#toString(java
	 * .lang.Object)
	 */
	@Override
	public String toString(double[] position) {
		DecimalFormat df = new DecimalFormat("#####0.0000");
		String temp = "(" + df.format(position[0]);
		for (int i = 1; i < position.length; i++) {
			temp += ";" + df.format(position[i]);
		}
		return temp + ")";
	}

	@Override
	public double[] createPositiveVector(double percent) {
		double[] temp = new double[getDimensionality()];
		double[][] tempBoundaries = new double[getDimensionality()][2];
		if (getBoundaries() != null) {
			tempBoundaries = getBoundaries();
		} else {
			tempBoundaries=getStandardBounds();
		}
		for (int i = 0; i < getDimensionality(); i++) {
			temp[i] = percent
					* Math.abs(tempBoundaries[i][1] - tempBoundaries[i][0]);
		}
		return temp;
	}

	@Override
	public boolean checkBoundariesCompatibility() {
		if(getBoundaries()==null){
			return true;
		}
		if(!(getBoundaries() instanceof double[][])){
			return false;
		}
		double[][] test=(double[][]) getBoundaries();
		if(test.length!=getDimensionality()){
			return false;
		}
		if(test[0].length!=2){
			return false;
		}
		return true;
	}

	@Override
	public double[] getLowerBounds() {
		double[] lbound=new double[getDimensionality()]; 
		for(int i=0;i<getDimensionality();i++){
			lbound[i]=getBoundaries()[i][0];
		}
		return lbound;
	}

	@Override
	public double[] getUpperBounds() {
		double[] ubound=new double[getDimensionality()]; 
		for(int i=0;i<getDimensionality();i++){
			ubound[i]=getBoundaries()[i][1];
		}
		return ubound;
	}
	
	/**
	 * Standard lower bound for one dimension.
	 * @return standard lower bound
	 */
	public double[][] getStandardBounds() {
		double[][] tempBoundaries = new double[getDimensionality()][2];
		for (int i = 0; i < getDimensionality(); i++) {
			tempBoundaries[i][0] = stdLowerBound;
			tempBoundaries[i][1] = stdUpperBound;
		}
		return tempBoundaries;
	}

	@Override
	public double[] createVelocity(double vmax) {
		double[] vel=new double[getDimensionality()];
		for(int i=0;i<vel.length;i++){
			vel[i]=-vmax+(2*vmax*getParentOptimization().getRng().nextDouble());
		}
		return vel;
	}

}
